﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ServBus.ListForm2013.Setup.Commands;
using ServBus.ListForm2013.Setup.Utilities;

namespace ServBus.ListForm2013.Setup.SubForms
{
    public partial class OperationForm : BaseStepForm
    {
        private InstallBatch batchType;
        private bool isAbort = false;
        private List<BaseCommand> commands;
        private int cmdIndex = 0;
        private bool hasWrong = false;
        private bool hasDone = false;
        private bool firstSwitch = false;
        private System.Timers.Timer timer;
        private object locker = new object();
        private delegate void OperationFinished();
        private delegate void RunSingleOperation();

        private bool IsRollback
        {
            get
            {
                return hasWrong || isAbort;
            }
        }

        public OperationForm()
        {
            InitializeComponent();
        }

        public OperationForm(BaseStepForm previous, SetupForm setupForm, InstallBatch batchType)
            : base(previous, setupForm)
        {
            InitializeComponent();
            this.batchType = batchType;
        }

        public override string Title
        {
            get
            {
                switch (batchType)
                {
                    case InstallBatch.Install:
                        return Properties.Resources.BatchInstall;
                    case InstallBatch.Remove:
                        return Properties.Resources.BatchRemove;
                    case InstallBatch.Repair:
                        return Properties.Resources.BatchRepair;
                    default:
                        return Properties.Resources.BatchUpgrade;
                }
            }
        }

        public override string SubTitle
        {
            get
            {
                switch (batchType)
                {
                    case InstallBatch.Install:
                        return Properties.Resources.BatchInstallSubTitle;
                    case InstallBatch.Remove:
                        return Properties.Resources.BatchRemoveSubTitle;
                    case InstallBatch.Repair:
                        return Properties.Resources.BatchRepairSubTitle;
                    default:
                        return Properties.Resources.BatchUpgradeSubTitle;
                }
            }
        }

        public override void Init()
        {
            if (batchType != InstallBatch.Install)
                this.ParentSetupForm.AbortButton.Enabled = false;
            this.ParentSetupForm.PrevButton.Enabled = false;
            this.ParentSetupForm.NextButton.Enabled = false;
        }

        public override void Execute()
        {
            commands = new List<BaseCommand>();
            switch (batchType)
            {
                case InstallBatch.Install:
                    commands.Add(new ExtractSolutionCmd());
                    commands.Add(new AddSolutionCmd());
                    commands.Add(new DeploySolutionCmd());
                    commands.Add(new WaitingSolutionCmd());
                    commands.Add(new ActivateFeatureCmd());
                    commands.Add(new ClearTempCmd());
                    commands.Add(new IisResetCmd());
                    commands.Add(new TimerResetCmd());
                    commands.Add(new OpenSPCACmd());
                    break;
                case InstallBatch.Remove:
                    commands.Add(new DeactivateFeatureCmd());
                    commands.Add(new RetractSolutionCmd());
                    commands.Add(new WaitingSolutionCmd());
                    commands.Add(new DeleteSolutionCmd());
                    commands.Add(new IisResetCmd());
                    commands.Add(new TimerResetCmd());
                    break;
                case InstallBatch.Repair:
                    commands.Add(new ExtractSolutionCmd());
                    commands.Add(new UpgradeSolutionCmd());
                    commands.Add(new WaitingSolutionCmd());
                    commands.Add(new ActivateFeatureCmd());
                    commands.Add(new ClearTempCmd());
                    commands.Add(new IisResetCmd());
                    commands.Add(new TimerResetCmd());
                    commands.Add(new OpenSPCACmd());
                    break;
                case InstallBatch.Upgrade:
                    commands.Add(new ExtractSolutionCmd());
                    commands.Add(new UpgradeSolutionCmd());
                    commands.Add(new WaitingSolutionCmd());
                    commands.Add(new ActivateFeatureCmd());
                    commands.Add(new ClearTempCmd());
                    commands.Add(new IisResetCmd());
                    commands.Add(new TimerResetCmd());
                    commands.Add(new OpenSPCACmd());
                    break;
            }

            this.progressOperation.Maximum = commands.Count;
            this.progressOperation.Step = 1;
            timer = new System.Timers.Timer(500);
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            timer.Stop();
            if (firstSwitch)
            {
                firstSwitch = false;
                    if (hasWrong) cmdIndex -= 2;
                    else if (isAbort) cmdIndex -= 1;
            }
            int currentIndex = cmdIndex;
            int nextIndex = IsRollback ? cmdIndex -1 : cmdIndex + 1;
            if ((currentIndex >= commands.Count && !this.IsRollback) ||
                (currentIndex < 0 && this.IsRollback))
            {
                this.BeginInvoke(new OperationFinished(SetFinishState));
                return;
            }
            

            // Run single cmd
            this.BeginInvoke(new RunSingleOperation(RunSingleCommand));
            if (!IsRollback)
            {
                bool result = this.commands[currentIndex].Execute();
                if (!result && !hasWrong)
                {
                    hasWrong = true;
                    firstSwitch = true;
                    if (this.commands[currentIndex].AllowRollback)
                    {
                        // Rollback
                        this.BeginInvoke(new RunSingleOperation(RunSingleCommand));
                    }
                    else
                    {
                        // Exit
                        this.BeginInvoke(new OperationFinished(SetFinishState));
                        return;
                    }
                }
            }
            else
            {
                this.commands[currentIndex].Rollback();
            }

                cmdIndex = nextIndex;
            timer.Start();
        }

        private void RunSingleCommand()
        {
            if (cmdIndex < 0)
            {
                return;
            }
                if (!this.commands[cmdIndex].AllowRollback)
                    this.ParentSetupForm.AbortButton.Enabled = false;
                if (IsRollback)
                    this.labelOperation.Text = Properties.Resources.CmdRollback;
                else
                    this.labelOperation.Text = this.commands[cmdIndex].Description;
            if (IsRollback)
                this.progressOperation.Step = -1;
            this.progressOperation.PerformStep();
        }

        private void SetFinishState()
        {
            hasDone = true;
            this.ParentSetupForm.AbortButton.Enabled = true;
            this.ParentSetupForm.AbortButton.Text = Properties.Resources.DoneButton;
            if (hasWrong)
                this.labelOperation.Text = Properties.Resources.OptFailed;
            else if (isAbort)
                this.labelOperation.Text = Properties.Resources.OptAbort;
            else
                this.labelOperation.Text = Properties.Resources.OptSuccess;
            
        }

        public override void AbortSteup()
        {
            if (!hasDone)
            {
                isAbort = true;
                firstSwitch = true;
                Log.WriteLog(Log.LogType.Info, "User Cancelled.");
                this.ParentSetupForm.AbortButton.Enabled = false;
            }
            else
                Application.Exit();
        }
    }
}
